#include "Server.h"
#include "unistd.h"

#include "Partie.h"
#include "Etat.h"


#define DEBUG true



using namespace std;


Server::Server( int port )
{
	if(DEBUG)
	{ cout << "Lancement du serveur ..." << endl; }
	if(DEBUG)
	{ cout << "Adresse : " << sf::IpAddress::getPublicAddress() << endl; }
	if(DEBUG)
	{ cout << "Numero de port : " << port << " & " << port + 1 << endl; }

	this->listener_partie = new sf::TcpListener;
	this->selector_partie = new sf::SocketSelector;

	this->listener.listen( port );
	this->selector.add( listener );
	
	this->listener_partie->listen( port + 1 );
	this->selector_partie->add( *listener_partie );

	if(DEBUG)
	{ cout << "Serveur pret !" << endl << endl; }
}

Server::~Server()
{
	if(DEBUG)
	{ cout << "Fermeture du serveur ..." << endl; }

	for( map<string, Partie*>::iterator it = parties.begin(); it != parties.end(); it++ )
	{ delete (*it).second; }

	if(DEBUG)
	{ cout << "Parties supprimes !" << endl; }

	for( map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++ )
	{
		sf::Packet p;
		p << eMAIN_QUIT;
		(*it).second->BR->send( p );

		delete (*it).second;
	}

	if(DEBUG)
	{ cout << "Clients avertis et supprimes !" << endl; }
}


void Server::run()
{
	while( true )
	{
		usleep(5000);
		if( selector.wait( sf::milliseconds(60) ) ) /// ms ?
		{
			if( selector.isReady( listener ) )
			{
				if(DEBUG)
				{ cout << "Tentative connexion - Cote serveur ... " << endl; }

				this->ajouterClient();

				if(DEBUG)
				{ cout << endl; }
			}
			else
			{
				for( map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++)
				{

					usleep(5000);
			
					if( selector.isReady( *((*it).second->BR) ) )
					{
						sf::TcpSocket * socket_client = (*it).second->BR;

						int evenement;
						sf::Packet packet;

						socket_client->receive( packet );
						packet >> evenement;

						if(DEBUG)
						{ cout << "Nouvel evenement de \"" << (*it).first << "\" [" << evenement << "]" << endl; }

						switch( evenement )
						{

							// -------------------------------
							case eMAIN_ALLGAMES :
							{
								if(DEBUG)
								{ cout << "Demande : Liste des Parties ... " << endl; }
								
								packet.clear();
								packet << eMAIN_ALLGAMES;
								socket_client->send( packet );

								packet.clear();
								packet << parties.size();
								socket_client->send( packet );

								if(DEBUG)
								{ cout << parties.size() << " partie(s) envoyee(s)" << endl; }
							
								for( map<string, Partie*>::iterator s = parties.begin(); s != parties.end(); s++ )
								{
									packet.clear();
									packet << (*s).first << (sf::Uint8)(*s).second->getNbJoueur() << (sf::Uint8)(*s).second->getNbJoueurMax();
									socket_client->send( packet );

									if(DEBUG)
									{ cout << "\t- " << (*s).first << endl; }
								}
							} break;


							// -------------------------------
							case eMAIN_ALLCLIENTS :
							{
								if(DEBUG)
								{ cout << "Demande : Liste des Clients ..." << endl; }

								packet.clear();
								packet << eMAIN_ALLCLIENTS;
								socket_client->send( packet );

								packet.clear();
								packet << clients.size();
								socket_client->send( packet );

								if(DEBUG)
								{ cout << clients.size() << " client(s) envoye(s)" << endl; }

								for(map<string, Client*>::iterator itr = clients.begin(); itr != clients.end(); itr++)
								{
									cout << "\t- " << (*itr).first << endl;
									packet.clear();
									packet << (*itr).first;
									socket_client->send( packet );
								}
							} break;


							// -------------------------------
							case eNEW_GAME :
							{
								if(DEBUG)
								{ cout << "Demande : Creation nouvelle partie" << endl; }
								
								string nom_game;
								sf::Uint8 nb_j;

								packet.clear();
								socket_client->receive( packet );
								packet >> nom_game >> nb_j;

								if(DEBUG)
								{ cout << "Nom souhaite : " << nom_game << endl; }

								sf::Packet p;

								sf::Uint8 ok = 0;

								if( parties.find(nom_game) == parties.end() )
								{
									parties[nom_game] = new Partie( (int)nb_j, this->listener_partie, this->selector_partie );
									cout << "h" << endl;
									ajouterClientDansPartie( *it, nom_game, true );

									if(DEBUG)
									{ cout << "Partie Ajoute !" << endl; }
								}
								else
								{
									p << eCREATE_GAME;
									(*it).second->BR->send( p );

									p.clear();
									p << ok;
									(*it).second->BR->send( p );

									if(DEBUG)
									{ cout << "Partie deja existante" << endl; }
								}
							} break;


							// -------------------------------
							case eJOIN_GAME :
							{
								if(DEBUG)
								{ cout << "Demande : Rejoindre une partie" << endl; }

								string nom_game;

								packet.clear();
								socket_client->receive( packet );
								packet >> nom_game;

								if(DEBUG)
								{ cout << "Partie a rejoindre : " << nom_game << endl; }

								ajouterClientDansPartie( (*it), nom_game, false);
							} break;


							// -------------------------------
							case eLAUNCH :
							{
								if(DEBUG)
								{ cout << "Demande : Lancement d'une partie" << endl; }

								string nom_game;
								nom_game = (*it).second->nom_game;
		
								if(DEBUG)
								{ cout << "Partie a lancer : " << nom_game << endl; }
								
								demarrerPartie( nom_game );
							} break;


							// -------------------------------
							case eMAIN_DECOCLIENT :
							{
								if(DEBUG)
								{ cout << "Demande : Deconnexion de " << (*it).first << endl; }

								string nom = (*it).first;

								if(clients[nom]->nom_game != "")
								{
									supprimerClientDePartie((*it), clients[nom]->nom_game);
								}

								supprimerClient(nom);

								if(DEBUG)
								{ cout << "Deco de : " << nom << endl; }
	
								for(map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++)
								{
									sf::Packet pp;
									pp << eMAIN_DECOCLIENT;
									(*it).second->BR->send( pp );

									pp.clear();
									pp << nom;
									(*it).second->BR->send( pp );
								}
							} break;
							

							// -------------------------------
							case eMAIN_READY :
							{
								if(DEBUG)
								{ cout << "Demande : \"Je suis pret\" de " << (*it).first << endl; }

								string nomPartie = (*it).second->nom_game;

								parties[nomPartie]->setReady( (*it).first );

								if(parties[nomPartie]->allReady())
								{
									demarrerPartie(nomPartie);
								}
							} break;


							// -------------------------------
							case eMAIN_NEWMSG :
							{
								if(DEBUG)
								{ cout << "Demande : Nouveau message " << endl; }

								string msg;

								packet.clear();
								socket_client->receive( packet );
								packet >> msg;

								if(DEBUG)
								{ cout << "Message : " << msg << endl; }

								for(map<string, Client*>::iterator itr = clients.begin(); itr != clients.end(); itr++)
								{
									packet.clear();
									packet << eMAIN_NEWMSG;
									(*itr).second->BR->send( packet );
									//sendToAll( packet);

									packet.clear();
									packet << msg;
									(*itr).second->BR->send( packet );
									//sendToAll(packet);
								}

								if(DEBUG)
								{ cout << "Message envoye" << endl; }
							} break;

							// -------------------------------
							case eMAIN_DELCLSALON :
							{
								if(DEBUG)
								{ cout << "Demande : Deconnexion partie de " << (*it).first << endl; }

								supprimerClientDePartie( (*it), (*it).second->nom_game );
							} break;



							// -------------------------------
							default :
								if(DEBUG)
								{ cout << "Erreur : Evenement Inconnu" << endl; }
								break;
						}

						if(DEBUG)
						{ cout << "Termine !" << endl << endl; }
					}
				}
			}
		}

		if( selector_partie->wait( sf::milliseconds(60) ) ) // ms ?
		{
			if( selector_partie->isReady( *listener_partie ) )
			{
				if(DEBUG)
				{ cout << "Tentative connexion - Cote partie ..." << endl; }

				ajouterclientBRPartie();

				if(DEBUG)
				{ cout << endl; }
			}
		}
	}
}


void Server::ajouterClient()
{
	Client * new_client = new Client;
	new_client->nom_game = "";
	new_client->BR = new sf::TcpSocket;

	if( listener.accept( *(new_client->BR) ) == sf::Socket::Done )
	{
		selector.add( *(new_client->BR) );

		sf::Packet packet;
		string nom;
		if( new_client->BR->receive( packet ) == sf::Socket::Done )
		{
			packet >> nom;
			if(DEBUG)
			{ cout << "Nom du nouveau client : " << nom << endl; }

			sf::Uint8 ok = 0;

			if( clients.find( nom ) == clients.end() )
			{
				clients[nom] = new_client;
				
				ok = 1;
				packet.clear();
				packet << ok;
				clients[nom]->BR->send( packet );

				if(DEBUG)
				{ cout << "Client ajoute !" << endl; }

				
				for(map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++)
				{
					if(nom != (*it).first)
					{
						sf::Packet p;
						p << eMAIN_NEWCLIENT;
						(*it).second->BR->send( p );

						p.clear();
						p << nom;
						(*it).second->BR->send( p );
					}
				}
			}
			else
			{
				packet.clear();
				packet << ok;
				new_client->BR->send( packet );

				delete new_client;

				if(DEBUG)
				{ cout << "Rejete : Nom deja utilise ! " << endl; }
			}
		}
	}
	else
	{
		if(DEBUG)
		{ cout << "Erreur de connexion" << endl; }
		delete new_client;
	}
}

void Server::ajouterclientBRPartie()
{
	sf::TcpSocket * BR = new sf::TcpSocket;
	if( listener_partie->accept( *BR ) == sf::Socket::Done)
	{
		if(DEBUG)
		{ cout << "Connexion etablie" << endl; }

		sf::Packet packet;
		string nom;
		if( BR->receive( packet ) == sf::Socket::Done )
		{
			packet >> nom;
			
			if(DEBUG)
			{ cout << "Demande de : " << nom << endl; }

			sf::Uint8 ok = 0;

			if(clients.find(nom) != clients.end() )
			{
				clients[nom]->BR_partie = BR;

				ok = 1;
				packet.clear();
				packet << ok;
				clients[nom]->BR_partie->send( packet );
				//sendTo( clients[nom], packet);

				if(DEBUG) 
				{ cout << "Client ajoute" << endl; }

				selector_partie->add( * clients[nom]->BR_partie );
				
			}
			else
			{
				packet.clear();
				packet << ok;
				BR->send( packet );

				delete BR;

				if(DEBUG)
				{ cout << "Client inconnu" << endl; }
			}
		}
	}
	else
	{
		if(DEBUG)
		{ cout << "Erreur connexion" << endl; }
	}
}


void Server::supprimerClient( string client )
{
	if(DEBUG)
	{ cout << "Suppression de : " << client << endl; }

	selector.remove( *clients[client]->BR );

	delete clients[client];
	clients.erase( client );

	/*sf::Packet packet;
	packet << eMAIN_DECOCLIENT << client;	

	for(map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++)
	{
		(*it).second->BR->send( packet );
	}*/
}



void Server::ajouterClientDansPartie( pair<string,Client *> client, string nomPartie, bool newGame )
{
	sf::Packet packet;
	
	if(newGame) { packet << eCREATE_GAME; }
	else { packet << eJOIN_GAME; }

	client.second->BR->send ( packet );
	packet.clear();
	
	sf::Uint8 ok = 0;
	if( parties.find( nomPartie ) != parties.end() )
	{
		if( parties[ nomPartie ]->ajouterJoueur( client ) )
		{
			ok = 1;
			packet << ok;
			client.second->nom_game = nomPartie;

			if(DEBUG)
			{ cout << "Ajout effectue" << endl; }
	
			
		}
		else
		{
			ok = 2;
			packet << ok;

			if(DEBUG)
			{ cout << "Partie Pleine" << endl; }
		}
	}
	else
	{
		packet << ok;

		if(DEBUG)
		{ cout << "Partie inexistante" << endl; }
	}
	
	client.second->BR->send( packet );

	if(ok == 1)
	{
		if(newGame)
		{
			for(map<string, Client*>::iterator itr = clients.begin(); itr != clients.end(); itr++)
			{
				packet.clear();
				packet << eMAIN_NEWGAME;
				(*itr).second->BR->send( packet );

				packet.clear();
				
				packet << nomPartie << (sf::Uint8)parties[nomPartie]->getNbJoueur() << (sf::Uint8)parties[nomPartie]->getNbJoueurMax();
				(*itr).second->BR->send( packet );
			}
		}

		for(map<string, Client*>::iterator its = clients.begin(); its != clients.end(); its++)
		{
			sf::Packet packet;
			packet << eMAIN_ADDPARTIE;
			(*its).second->BR->send( packet );

			packet.clear();
			packet << nomPartie;
			(*its).second->BR->send( packet );
		}
		
		parties[nomPartie]->infoNewJoueur( client );
	}
}


void Server::supprimerClientDePartie( pair<string, Client*> client, string nomPartie )
{
	if(DEBUG)
	{ cout << "Suppression de : " << client.first << " de la partie : " << nomPartie << endl; }

	if( parties.find( nomPartie ) != parties.end() )
	{
		bool ok = parties[nomPartie]->retirerJoueur( client );
		clients[ client.first ]->nom_game = "";
			
		for(map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++)
		{
			sf::Packet packet;
			packet << eMAIN_RMPARTIE;
			(*it).second->BR->send( packet );

			packet.clear();
			packet << nomPartie;
			(*it).second->BR->send( packet );
		}

		if(ok == false)
		{ supprimerPartie( nomPartie ); }
	}
}


void Server::demarrerPartie( string nomPartie )
{
	if( parties.find(nomPartie) != parties.end() )
	{

		if(DEBUG)
		{ cout << "Lancement OK" << endl; }
		
		sf::Packet packet;
		packet << eLAUNCH;
		for(map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++)
		{
			if((*it).second->nom_game == nomPartie)
			{
				(*it).second->BR_partie->send( packet );
			}
		}

		cout << "X" << endl;

		uid_t fils = fork();
		switch( fils )
		{
			case -1 :
				cerr << "Erreur : fork() " << endl;
				break;

			case 0 :
				cout << "go" << endl;
				//parties[nomPartie]->sendMap();
				parties[nomPartie]->run();
				//supprimerPartie(nomPartie);
				exit(0);
				break;

			default :
				cout << "continu" << endl;
				supprimerPartie( nomPartie );
				break;
		}
	}
	else
	{
		if(DEBUG)
		{ cout << "Partie a lancer inexistante" << endl; }
	}
}

void Server::supprimerPartie( string nomPartie )
{
	parties.erase( nomPartie );

	for(map<string, Client*>::iterator it = clients.begin(); it != clients.end(); it++)
	{
		sf::Packet packet;
		packet << eMAIN_DECOGAME;
		(*it).second->BR->send( packet );

		packet.clear();
		packet << nomPartie;
		(*it).second->BR->send( packet );
	}

	if(DEBUG) { cout << "Suppression de Partie" << endl; }
}




